function GetEle(selector) {
    this.eles = document.querySelectorAll(selector);
}
GetEle.prototype.html = function (con) {
    // this -> 调用此方法的实例化对象  {eles:[]}
    if (arguments.length >= 1) { //有参数(至少一个)
        // for (var i = 0; i < this.eles.length; i++) {
        //     var ele = this.eles[i];
        //     ele.innerHTML = con;
        // }

        // this -> 调用此方法的实例化对象  -> 可以访问原型对象(prototype)所有的方法
        this.each(function (ele, index) {
            ele.innerHTML = con;
        })
        return this;
    } else { //没有参数
        return this.eles[0].innerHTML;
    }
}
GetEle.prototype.text = function (con) {
    // this -> 调用此方法的实例化对象  {eles:[]}
    if (arguments.length >= 1) { //有参数(至少一个)
        // for (var i = 0; i < this.eles.length; i++) {
        //     var ele = this.eles[i];
        //     ele.innerText = con;
        // }

        this.each(function (ele, index) {
            ele.innerText = con;
        })
        return this;
    } else { //没有参数
        return this.eles[0].innerText;
    }
}
GetEle.prototype.val = function (con) {
    // this -> 调用此方法的实例化对象  {eles:[]}
    if (arguments.length >= 1) { //有参数(至少一个)
        // for (var i = 0; i < this.eles.length; i++) {
        //     var ele = this.eles[i];
        //     ele.value = con;
        // }
        this.each(function (ele, index) {
            ele.value = con;
        })
        return this;
    } else { //没有参数
        return this.eles[0].value;
    }
}
GetEle.prototype.hide = function () {
    // this -> 调用此方法的实例化对象  {eles:[]}
    // for (var i = 0; i < this.eles.length; i++) {
    //     var ele = this.eles[i];
    //     ele.style.display = "none";
    // }

    this.each(function (ele, index) {
        ele.style.display = "none";
    })
    return this;

}
GetEle.prototype.show = function () {
    // this -> 调用此方法的实例化对象  {eles:[]}
    // for (var i = 0; i < this.eles.length; i++) {
    //     var ele = this.eles[i];
    //     ele.style.display = "block";
    // }

    this.each(function (ele, index) {
        ele.style.display = "block";
    })
    return this;

}
GetEle.prototype.each = function (fn) {
    // this -> 调用此方法的实例化对象  {eles:[]}
    for (var i = 0; i < this.eles.length; i++) {
        var ele = this.eles[i];
        var index = i;

        //  注意  jquery中 fn(index,ele)  第一参数:下标  第二个:元素
        // fn(ele, index);   // this -> window

        fn.call(ele, ele, index);  // fn中的this指向循环当前的元素
    }
    return this;
}

// on(eventType,callback)
GetEle.prototype.on = function (eventType, fn) {
    // this -> 调用此方法的实例化对象  {eles:[]}
    // for (var i = 0; i < this.eles.length; i++) {
    //     var ele = this.eles[i];
    //     var index = i;
    //     try {
    //         ele.addEventListener(eventType, fn);
    //     } catch (err) {
    //         ele.attachEvent("on" + eventType, fn);
    //     }
    // }
    this.each(function (ele) {
        try {
            ele.addEventListener(eventType, fn);
        } catch (err) {
            ele.attachEvent("on" + eventType, fn);
        }
    })
    return this;
}

GetEle.prototype.off = function (eventType, fn) {
    // this -> 调用此方法的实例化对象  {eles:[]}
    this.each(function (ele) {
        try {
            ele.removeEventListener(eventType, fn);
        } catch (err) {
            ele.detachEvent("on" + eventType, fn);
        }
    })
    return this;
}

// click事件 是由on方法二次封装完成的  (可以给一个元素绑定多个事件)
GetEle.prototype.click = function (fn) {
    // this -> 调用此方法的实例化对象  {eles:[]}   -> 也可以访问原型对象(prototype)所有的方法
    this.on("click", fn);
    return this;
}
GetEle.prototype.dblclick = function (fn) {
    // this -> 调用此方法的实例化对象  {eles:[]}   -> 也可以访问原型对象(prototype)所有的方法
    this.on("dbclick", fn);
    return this;
}
GetEle.prototype.mousedown = function (fn) {
    // this -> 调用此方法的实例化对象  {eles:[]}   -> 也可以访问原型对象(prototype)所有的方法
    this.on("mousedown", fn);
    return this;
}
GetEle.prototype.mouseup = function (fn) {
    // this -> 调用此方法的实例化对象  {eles:[]}   -> 也可以访问原型对象(prototype)所有的方法
    this.on("mouseup", fn);
    return this;
}
GetEle.prototype.mousemove = function (fn) {
    // this -> 调用此方法的实例化对象  {eles:[]}   -> 也可以访问原型对象(prototype)所有的方法
    this.on("mousemove", fn);
    return this;
}

// width()  获取和设置 元素的宽度
// width("200px")  有参数 => 设置
// width()         没有参数 => 获取  


GetEle.prototype.width = function (con) {
    // debugger;
    // this -> 调用此方法的实例化对象  {eles:[]}   -> 也可以访问原型对象(prototype)所有的方法
    if (arguments.length >= 1) {
        this.each(function (ele) {
            // con 可能有单位  也可能没有单位
            // 有单位(100px % pt em rem vw vh ) => 直接赋值
            // 没有单位(100) => 默认单位px

            var reg = /^\d+(px|%|pt|em|rem|vw|vh)$/
            if (reg.test(con)) { // 有单位
                ele.style.width = con;
            } else {
                ele.style.width = con + "px";
            }
        })
        return this;
    } else {
        return parseInt(this.getStyle("width"));
        // return  this.eles[0].style.width; style只能获取内联样式
    }
}

GetEle.prototype.height = function (con) {
    // debugger;
    // this -> 调用此方法的实例化对象  {eles:[]}   -> 也可以访问原型对象(prototype)所有的方法
    if (arguments.length >= 1) {
        this.each(function (ele) {
            // con 可能有单位  也可能没有单位
            // 有单位(100px % pt em rem vw vh ) => 直接赋值
            // 没有单位(100) => 默认单位px

            var reg = /^\d+(px|%|pt|em|rem|vw|vh)$/
            if (reg.test(con)) { // 有单位
                ele.style.height = con;
            } else {
                ele.style.height = con + "px";
            }
        })
        return this;
    } else {
        return parseInt(this.getStyle("height"));
        // return  this.eles[0].style.width; style只能获取内联样式
    }
}

// css()    获取和设置 元素的css演示
// css("background","red")   有两个参数 => 设置
// css("background")         一个参数 => 获取  

GetEle.prototype.css = function (attr, val) {
    if (arguments.length >= 2) { // 有两个参数
        this.each(function (ele) {
            ele.style[attr] = val;
        })
        return this;
    } else {
        // 一个参数   1. css("background")  2. css({background:"red"})
        if (attr.constructor === Object) {
            for (var key in attr) {
                var val = attr[key];
                this.css(key, val);
            }
            return this;
        } else {
            return this.getStyle(attr);
        }
        // return this.eles[0].style[attr];
    }
}



GetEle.prototype.getStyle = function (attr) {
    // debugger;
    // this -> 调用此方法的实例化对象  {eles:[]}   -> 也可以访问原型对象(prototype)所有的方法
    var ele = this.eles[0];
    try {
        return window.getComputedStyle(ele)[attr];
    } catch (err) {
        return ele.currentStyle[attr];
    }
}

// attr()    获取和设置 html属性(属性节点)
// attr("data-index","0")     有两个参数 => 设置
// attr("data-index")         一个参数 => 获取  
GetEle.prototype.attr = function (key, val) {
    // this -> 调用此方法的实例化对象  {eles:[]}   -> 也可以访问原型对象(prototype)所有的方法
    if (arguments.length >= 2) {
        this.each(function (ele) {
            ele.setAttribute(key, val);
        })
        return this;
    } else {
        return this.eles[0].getAttribute(key);
    }
}

// prop()    获取和设置 元素节点的属性 ele.id
// prop("id","demo")  有两个参数 => 设置
// prop("id")         一个参数 => 获取  
GetEle.prototype.prop = function (key, val) {
    // this -> 调用此方法的实例化对象  {eles:[]}   -> 也可以访问原型对象(prototype)所有的方法
    if (arguments.length >= 2) {
        this.each(function (ele) {
            ele[key] = val;
        })
        return this;
    } else {
        return this.eles[0][key];
    }
}

// addClass()   向匹配的元素中新增一个或多个class名(多个class名用空格分隔 "one two three")
GetEle.prototype.addClass = function (classCon) {
    // debugger;
    // this -> 调用此方法的实例化对象  {eles:[]}   -> 也可以访问原型对象(prototype)所有的方法
    if (arguments.length >= 1) {
        var list = classCon.split(/\s/g);
        this.each(function (ele) {
            ele.classList.add(...list);
        })
    }
    return this;
}

// removeClass()   删除匹配的元素中一个或多个class名(多个class名用空格分隔)
GetEle.prototype.removeClass = function (classCon) {
    // debugger;
    // this -> 调用此方法的实例化对象  {eles:[]}   -> 也可以访问原型对象(prototype)所有的方法
    if (arguments.length >= 1) {
        var list = classCon.split(/\s/g);
        this.each(function (ele) {
            ele.classList.remove(...list);
        })
    }
    return this;
}

// 链式操作 => 调用方法得到的返回 还是相同类型的数据

// var arr = [];
// arr.concat(1,2).concat(3,4).concat(5,6);

// "YY-MM-DD".replace("YY", "2021").replace("MM", "09")

// var s = new Set();
// s.add(1).add(2).add(3);

// Promise.resolve(1).then().then().then()


// 链式操作   => 调用方法得到的返回 还是相同类型的数据(实例化对象)
// $(".list li").eq(0).css({ background: "red" });

// 问题:   
// $(".list li").eq(0)  => 返回原生dom元素  <li>01</li>  没有办法继续调用css方法

// 解决方法:
// 用新的集合替换原本的集合  => 返回该实例化对象

// eq(index)     匹配对应下标的元素 => 形成的实例化对象

GetEle.prototype.eq = function (index) {
    // this -> 调用此方法的实例化对象  {eles:[li,li,li,li,li,li]}   -> 也可以访问原型对象(prototype)所有的方法

    // return this.eles[index];  // 原生dom元素 

    var ele = this.eles[index]; // 对应下标的元素   <li></li>
    this.eles = [ele]; // [li]   对应下标的元素=>形成的集合
    return this;
}

// $(".list li").eq(0).siblings().css({background:"blues"});

// $(ele).siblings()     获取除匹配元素之外的所有同级元素

GetEle.prototype.siblings = function (index) {
    // this -> 调用此方法的实例化对象  {eles:[li]}   -> 也可以访问原型对象(prototype)所有的方法

    var ele = this.eles[0]; // 被选中的元素  => 如何找到他所有的同级元素
    var parentEle = ele.parentElement;
    var children = parentEle.children;
    var list = Array.from(children).filter(item => item !== ele); // 除了被选中元素以外的其他同级元素

    this.eles = list; //   对应下标的元素=>形成的集合
    return this;
}



/* function getStyle(ele, attr) {
    try {
        return window.getComputedStyle(ele)[attr];
    } catch (err) {
        return ele.currentStyle[attr];
    }
} */


//  问题1: 每次操作元素 必须先得到实例化对象 在操作  => 麻烦
//  解决方法 快速根据选择器得到实例化对象   => 对已有的构造函数进行二次封装

function $(selector) {
    return new GetEle(selector);
}